package cubelabs.nexus.controller;

import cubelabs.nexus.domain.CalendarDTO;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import cubelabs.nexus.domain.CategoryDTO;
import cubelabs.nexus.domain.CounselEventCreationRequest;
import cubelabs.nexus.domain.CounselRequestDTO;
import cubelabs.nexus.domain.CounselRequestResponse;
import cubelabs.nexus.domain.CouponDTO;
import cubelabs.nexus.domain.FileUploadResponseDTO;
import cubelabs.nexus.domain.InvitationDTO;
import cubelabs.nexus.domain.NexusFileUpload;
import cubelabs.nexus.domain.OneToMany;
import cubelabs.nexus.domain.SessionDTO;
import cubelabs.nexus.domain.SessionData;
import cubelabs.nexus.domain.Stats;
import cubelabs.nexus.domain.UserDTO;
import cubelabs.nexus.domain.UserSearchDTO;
import cubelabs.nexus.entity.Category;
import cubelabs.nexus.entity.CounsellingSession;
import cubelabs.nexus.entity.Event;
import cubelabs.nexus.entity.Invitation;
import cubelabs.nexus.entity.Organization;
import cubelabs.nexus.entity.Session;
import cubelabs.nexus.entity.User;
import cubelabs.nexus.entity.Viewer;
import cubelabs.nexus.enums.InvitationStatus;
import cubelabs.nexus.enums.SessionStatus;
import cubelabs.nexus.service.NexusService;
import cubelabs.nexus.utils.GenericUtils;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

	private static final Logger logger = LoggerFactory
			.getLogger(HomeController.class);

	@Autowired
	private NexusService nexuService;


	@RequestMapping(value="/")
	public ModelAndView homePage(){

		ModelAndView mv = new ModelAndView();
		mv.setViewName("index");
		return mv;
	}



	@RequestMapping(value="/checkLogin",method=RequestMethod.GET)
	public @ResponseBody UserDTO login(HttpServletRequest request,HttpServletResponse response) throws Exception {

		User loggedInUser = (User) request.getSession().getAttribute("user");

		UserDTO userDTO = null;

		if(loggedInUser != null){

			userDTO = new UserDTO();
			userDTO.setEmail(loggedInUser.getEmail());
			userDTO.setName(loggedInUser.getName());
			userDTO.setImagePath(loggedInUser.getImagePath());
			userDTO.setId(loggedInUser.getId());

		}


		return userDTO;
	}




	@RequestMapping(value="/stats",method=RequestMethod.GET)
	public @ResponseBody Stats stats(HttpServletRequest request,HttpServletResponse response) throws Exception {
		Stats stats = new Stats();

		stats.userBase=1000;
		stats.advisesDelivered=100;
		stats.noOfExperts=20;
		stats.noOfSubjects=10;


		return stats;
	}

	/**
	 * Simply selects the user by userId.
	 */
	@RequestMapping(value = "/myprofile", method = RequestMethod.GET)
	public @ResponseBody
	UserDTO getMyProfile(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		User loggedInUser = (User) request.getSession().getAttribute("user");
		return nexuService.findUserDetails(loggedInUser.getId());
	}

	/**
	 * Simply selects the user by userId.
	 */
	@RequestMapping(value = "/updateProfile", method = RequestMethod.POST)
	public @ResponseBody
	boolean updateProfile(@RequestBody UserDTO userDTO, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		nexuService.copyUserDTOToUser(userDTO);

		return true;
	}


	/**
	 * Simply selects the user by userId.
	 */
	@RequestMapping(value = "/user/{id}")
	public @ResponseBody
	UserDTO getUserById(@PathVariable("id") Long userId,
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		return nexuService.findUserDetails(userId);
	}

	/**
	 * Simply selects the user by categoryId.
	 */
	@RequestMapping(value = "/category/{id}")
	public @ResponseBody
	List<UserSearchDTO> getUsersByCategory(
			@PathVariable("id") Long categoryId,
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		//UserResponse userResponse = new UserResponse();
		User user = (User) request.getSession().getAttribute("user");

		return nexuService.fetchUsersByCategoryId(categoryId,user);
	}

	@RequestMapping(value = "/search")
	public @ResponseBody
	List<UserSearchDTO> getAllUsers()
			throws Exception {

		return nexuService.fetchAllUsers();
	}

	/**
	 * Simply selects the list of categories.
	 */
	@RequestMapping(value = "/category")
	public @ResponseBody
	List<CategoryDTO> getCategories(HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		//CategoryResponse categoryResponse = new CategoryResponse();
		List<Category> categories = nexuService.findAllCategories();
		List<CategoryDTO> categoryDTOList = new ArrayList<CategoryDTO>();
		if(categories != null){
			for(Category category : categories){
				CategoryDTO categoryDTO = new CategoryDTO();
				categoryDTO.setId(category.getId());
				categoryDTO.setName(category.getName());
				categoryDTOList.add(categoryDTO);
			}
		}

		return categoryDTOList;
	}

	@RequestMapping(value = "/trendingCategories")
	public @ResponseBody
	List<CategoryDTO> getTrendingCategories(HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		List<Category> categories = nexuService.findTrendingCategories();
		List<CategoryDTO> categoryDTOList = new ArrayList<CategoryDTO>();
		if(categories != null){
			for(Category category : categories){
				CategoryDTO categoryDTO = new CategoryDTO();
				categoryDTO.setId(category.getId());
				categoryDTO.setName(category.getName());
				categoryDTOList.add(categoryDTO);
			}
		}

		return categoryDTOList;
	}


	/**
	 * Simply selects the list of counsel requests for user.
	 */
	
	@RequestMapping(value = "/requests")
	public @ResponseBody
	List<CounselRequestDTO> getCounselRequestsForUser(
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		User user = (User) request.getSession().getAttribute("user");
		//TODO
		//Hard Coding for now will change later		
		//CounselRequestResponse counselRequestResponse = new CounselRequestResponse();
		List<CounselRequestDTO> counselRequestDTOList = nexuService
				.findCounselRequestsByUserId(user.getId());

		return counselRequestDTOList;
	}
	



	/**
	 * Simply selects the list of counsel requests for user.
	 */
	@RequestMapping(value = "/notifications")
	public @ResponseBody
	List<InvitationDTO> getNotifications(
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		User user = (User) request.getSession().getAttribute("user");
		return nexuService.findNotifications(user.getId());
	}

	/**
	 * Simply selects the list of counsel requests for user.
	 */
	/*
	@RequestMapping(value = "/pendingRequests")
	public @ResponseBody
	List<CounselRequestDTO> getCounselPendingRequestsForUser(
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		User user = (User) request.getSession().getAttribute("user");

		//CounselRequestResponse counselRequestResponse = new CounselRequestResponse();
		List<CounselRequestDTO> counselRequestDTOList = nexuService
				.findCounselPendingRequestPerUserId(user.getId());

		return counselRequestDTOList;
	}
	*/
	/**
	 * Simply selects the list of counsel requests for user.
	 */
	@RequestMapping(value = "/counsel/{sessionId}/{status}")
	public @ResponseBody
	String approveRequest(
			@PathVariable("sessionId") Long sessionId,
			@PathVariable("status") String status, HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		User user = (User) request.getSession().getAttribute("user");


		InvitationStatus invitationStatus = null;

		if(status.equals("Approve")){
			invitationStatus = InvitationStatus.ACCEPTED;
		}else {
			invitationStatus = InvitationStatus.REJECTED;
		}

		return nexuService.updateSession(sessionId,user.getId(),invitationStatus);
	}

	
	@RequestMapping(value = "/experttalk/{sessionId}/{status}")
	public @ResponseBody
	String approveExpertTalkRequest(
			@PathVariable("sessionId") Long sessionId,
			@PathVariable("status") String status, HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		User user = (User) request.getSession().getAttribute("user");


		InvitationStatus invitationStatus = null;

		if(status.equals("Approve")){
			invitationStatus = InvitationStatus.ACCEPTED;
		}else {
			invitationStatus = InvitationStatus.REJECTED;
		}

		return nexuService.updateExpertTalk(sessionId,user.getId(),invitationStatus);
	}

	
	@RequestMapping(value = "counsel/{userId}/addCounselRequest")
	public @ResponseBody
	CounselRequestResponse addCounselRequest(@RequestBody CounselEventCreationRequest counselEventCreationRequest,@PathVariable("userId") Long toUserId,
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		System.out.println(request.getSession().getAttribute("user"));
		User frmUser = (User) request.getSession().getAttribute("user");


		User toUser = nexuService.fetchUserById(toUserId);

		//CounsellingEvent counsellingEvent = new CounsellingEvent();
		//counsellingEvent.setActive(true);
		//counsellingEvent.setDiscription(counselEventCreationRequest.getDescription());
		//counsellingEvent.setFrmUser(frmUser);

		Category category = nexuService.fetchCategoryByName(counselEventCreationRequest.getCategoryName());
		//counsellingEvent.setCategoryId(category.getId());
		//counsellingEvent.setCounsellingAcceptor(counsellingAcceptor);
		//counsellingEvent.setToUser(toUser);
		Date startDate;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

		startDate = sdf.parse(counselEventCreationRequest.getStartTime());
		//counsellingEvent.setStart(startDate);

		Date endDate;
		endDate = sdf.parse(counselEventCreationRequest.getEndTime());
		//counsellingEvent.setEnd(endDate);
		//counsellingEvent.setCounsellingEventStatus(CounsellingEventStatus.InActive);


		//                //check avaliality of expert -- have to uncomment once the registration flow is completed
		//                if(!nexuService.checkAvaliability(startDate, endDate, toUser)){
		//                      //Have to return error 
		//                    return null;
		//                }
		//Check for expert conflits
		if(!nexuService.checkForConflits(startDate,endDate,toUser)){
			//Have to return error 
			return null;
		}
		//check for user conflits
		if(!nexuService.checkForConflits(startDate,endDate,frmUser)){
			//Have to return error 
			return null;
		}

		//nexuService.createEvent(counsellingEvent);

		CounselRequestResponse counselRequestResponse = new CounselRequestResponse();
                if(frmUser!=null){
                    List<CounselRequestDTO> counselRequestDTOList = nexuService
                                    .findCounselRequestsByUserId(frmUser.getId());

                    counselRequestResponse.setCounselRequestDTO(counselRequestDTOList);
                }
		Session session = new Session();
		session.setOneToMany(false);
		session.setMaxSeats(1);
		session.setExpert(toUser);
	
		Viewer viewer = new Viewer();
		
		if(frmUser != null) {
			viewer.setUser(frmUser);
		} else {
			viewer.setEmail(counselEventCreationRequest.getEmail());
		}
		viewer.setSession(session);
		List<Viewer> viewers = new ArrayList<Viewer>();
		viewers.add(viewer);
		session.setViewers(viewers);
		Invitation invitation = new Invitation();
		invitation.setInvitee(toUser);
		invitation.setInviter(frmUser);
		invitation.setSession(session);
		invitation.setMessage(counselEventCreationRequest.getDescription());
		session.setExpertInvitation(invitation);
		session.setCategory(category);
		session.setStartTime(startDate);
		session.setTitle(counselEventCreationRequest.getDescription());
		session.setEndTime(endDate);
                session.setSessionStatus(SessionStatus.PENDINGAPPROVAL);
		nexuService.createSession(session);
		
		return counselRequestResponse;
	}


	@RequestMapping(value="/coupon/generateCoupon")
	public @ResponseBody String generateCoupon(@RequestBody CounselEventCreationRequest counselEventCreationRequest, HttpServletRequest request) throws Exception{

		User frmUser = (User) request.getSession().getAttribute("user");
		System.out.println(" generating coupon in process ");
		System.out.println(" frmUser : "+frmUser.getId());
		//UserCategory category = nexuService.addUserToCategory(categoryId, frmUser.getId());
		//userResponse.setUserDTOs(GenericUtils.getUserDTO(category.getUsers()));

		nexuService.generateCoupon(counselEventCreationRequest, frmUser,counselEventCreationRequest.getCount());

		return "success";
	}

	

	
	
	/**
	 * Simply selects the list of coupons for user.
	 */
	@RequestMapping(value = "/coupons")
	public @ResponseBody
	List<CouponDTO> getCoupons(
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		User user = (User) request.getSession().getAttribute("user");


		List<CouponDTO> couponDTOList = nexuService.findCouponListPerUser(user);

		return couponDTOList;
	}

	@RequestMapping(value="{counselEventId}/startSession")
	public @ResponseBody SessionData initSession(@PathVariable("counselEventId") Long counselEventId,  HttpServletRequest request, HttpServletResponse response){

		User user = (User) request.getSession().getAttribute("user");

		SessionData sessionData2 = nexuService.fetchSession(counselEventId, user.getId());
		if(sessionData2 == null){
			CounsellingSession counsellingSession = nexuService.saveCounsellingSession(counselEventId);
			sessionData2 = new SessionData();
			sessionData2.setApiKey(21313161);
			sessionData2.setModeratorToken(counsellingSession.getModeratorToken());
			sessionData2.setPublisherToken(counsellingSession.getPublisherToken());
			sessionData2.setSessionId(counsellingSession.getSessionId());
			sessionData2.setSubscriberToken(counsellingSession.getSubscriberToken());
			sessionData2.setToken(counsellingSession.getToken());
		}

		sessionData2.setUserName(user.getName());

		return sessionData2;
	}

	@RequestMapping(value="{counselEventId}/stopSession")
	public @ResponseBody String stopSession(@PathVariable("counselEventId") Long counselEventId, HttpServletRequest request,
			HttpServletResponse response){

		User user = (User) request.getSession().getAttribute("user");

		Session counsellingEvent = nexuService.stopSession(counselEventId);

		String responseStr = null;
		if(counsellingEvent != null && counsellingEvent.getExpert().getId().equals(user.getId())){
			responseStr = "rate";
		}else{
			responseStr = "dashboard";
		}
		return responseStr;
	}

	@RequestMapping(value = "counsel/{counselEventId}/rating")
	public @ResponseBody
	String rating(@PathVariable("counselEventId") Long counselEventId , @RequestParam("rating") Integer rating, @RequestParam("review") String review,  HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		User user = (User) request.getSession().getAttribute("user");

		return nexuService.rateCounselEvent(counselEventId, rating,review, user.getId());
	}
	
	@RequestMapping(value="counsel/{counselEventId}/uploadFile", method = RequestMethod.POST)
    public @ResponseBody List<FileUploadResponseDTO> upload(@PathVariable("counselEventId") Long counselEventId ,
    		HttpServletRequest request, HttpServletResponse response) throws IOException {
 
    	 MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
         Iterator<String> itr =  multipartRequest.getFileNames();
         MultipartFile mpf = null;
 
         List<FileUploadResponseDTO> fileUploadResponseDTOList = new ArrayList<FileUploadResponseDTO>();

         while(itr.hasNext()){
             //2.1 get next MultipartFile
             mpf = multipartRequest.getFile(itr.next());
             NexusFileUpload nexusFileUpload = new NexusFileUpload();
             nexusFileUpload.setMultiPartFile(mpf);
             
             FileUploadResponseDTO fileUploadResponseDTO = nexuService.uploadFileToAmazon(nexusFileUpload, counselEventId);

             fileUploadResponseDTOList.add(fileUploadResponseDTO);
         }
         return fileUploadResponseDTOList;
    }
	

	@RequestMapping(value = "counsel/{userId}/oneToMany")
	public @ResponseBody
	boolean oneToMany(@RequestBody OneToMany manyToOneRequest,
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		User frmUser = (User) request.getSession().getAttribute("user");
		nexuService.createOneToMany(manyToOneRequest, frmUser);
		return true;
	}

	@RequestMapping(value = "events/{counselEventId}/subscribe")
	public @ResponseBody String subscribe(@PathVariable("counselEventId") Long counselEventId ,  HttpServletRequest request,
			HttpServletResponse response) throws Exception {		
		User user = (User) request.getSession().getAttribute("user");
		nexuService.subscribe(counselEventId,  user.getId());
		return "sucess";
	}


	/*
	 * fetchExperts returns the experts whose name matches/contains the search string
	 */
	@RequestMapping(value = "/fetchExperts")
	public @ResponseBody
	List<UserSearchDTO> fetchExperts(@RequestBody String name, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		logger.info(" inside  fetchExperts ");
		List<UserSearchDTO> userDTOList = nexuService.fetchExperts(name);

		return userDTOList;
	}

	
	/*
	 * fetchExpertTalks returns the expert talks - one 2 many events
	 */
	@RequestMapping(value = "/fetchExpertTalks")
	public @ResponseBody
	List<SessionDTO> fetchExpertTalks(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		logger.info(" inside  fetchExpertTalks ");
		List<SessionDTO>  eventLst = nexuService.fetchExpertTalks();

		return eventLst;
	}


	/*
	 * fetchExpertTalks returns the expert talks(one 2 many events) filtered by expert 
	 */
	@RequestMapping(value = "/findExpertTalksByExpert")
	public @ResponseBody
	List<Event> findExpertTalksByExpert(@RequestBody String name, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		logger.info(" inside  findExpertTalksByExpert ");
		List<Event>  eventLst = nexuService.fetchExpertTalksByExpert(name);

		return eventLst;
	}
	
	
	@RequestMapping(value = "addFavExpert/{expertId}")
	public @ResponseBody
	String  addFavExpert(@PathVariable Long expertId, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		User user = (User) request.getSession().getAttribute("user");
		return nexuService.addFavoriteExpert(expertId, user);
	}
	
	@RequestMapping(value = "favorites")
	public @ResponseBody
	List<UserDTO>  getFavroites(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		User user = (User) request.getSession().getAttribute("user");
		return nexuService.getFavoriteExperts(user);
	}
	
        @RequestMapping(value = "user/(userId}/calander",method=RequestMethod.POST)
	public @ResponseBody
	CalendarDTO  getCalander(HttpServletRequest request,
			HttpServletResponse response,@PathVariable("id") Long userId,@RequestBody CalendarDTO calDto) throws Exception {
		User user = (User) request.getSession().getAttribute("user");
		return nexuService.getCalander(calDto.getStartDate(),calDto.getEndDate(), user, userId);
	}
        
}
